package service

import (
	"context"
	"errors"
	"github.com/wechatpay-apiv3/wechatpay-go/core"
	"github.com/wechatpay-apiv3/wechatpay-go/core/auth/verifiers"
	"github.com/wechatpay-apiv3/wechatpay-go/core/downloader"
	"github.com/wechatpay-apiv3/wechatpay-go/core/notify"
	"github.com/wechatpay-apiv3/wechatpay-go/core/option"
	"github.com/wechatpay-apiv3/wechatpay-go/services/payments/jsapi"
	"github.com/wechatpay-apiv3/wechatpay-go/services/payments/native"
	"github.com/wechatpay-apiv3/wechatpay-go/utils"
	"log/slog"
)

// NewWxpayService 微信支付
func NewWxpayService(configService *ConfigService) *WxpayService {
	return &WxpayService{ConfigService: configService}
}

// WxpayService 微信支付
type WxpayService struct {
	ConfigService *ConfigService

	mchid   string
	client  *core.Client
	handler *notify.Handler
}

func (service *WxpayService) Client() (*core.Client, error) {
	if service.client != nil {
		return service.client, nil
	}

	var cfg = service.ConfigService.Wxpay()
	service.mchid = cfg.Mchid

	// 使用 utils 提供的函数加载商户私钥，商户私钥会用来生成请求的签名
	mchPrivateKey, err := utils.LoadPrivateKey(cfg.MchPrivateKey)
	if err != nil {
		err = errors.New("load merchant private key error -> " + err.Error())
		return nil, err
	}
	// 使用商户私钥等初始化 client，并使它具有自动定时获取微信支付平台证书的能力
	opts := []core.ClientOption{
		option.WithWechatPayAutoAuthCipher(cfg.Mchid, cfg.MchSerial, mchPrivateKey, cfg.MchV3Secret),
	}
	service.client, err = core.NewClient(context.Background(), opts...)
	if err != nil {
		return nil, err
	}
	return service.client, nil
}

func (service *WxpayService) Jsapi() (*jsapi.JsapiApiService, error) {
	client, err := service.Client()
	if err != nil {
		return nil, err
	}
	return &jsapi.JsapiApiService{Client: client}, nil
}

func (service *WxpayService) Native() (*native.NativeApiService, error) {
	client, err := service.Client()
	if err != nil {
		return nil, err
	}
	return &native.NativeApiService{Client: client}, nil
}

// RSANotifyHandler 通知处理
// 使用方法： handler.ParseNotifyRequest(context.Background(), ctx.Request, t)
func (service *WxpayService) RSANotifyHandler(mchid string) (handler *notify.Handler, err error) {
	cfg := service.ConfigService.Wxpay()
	if cfg.Mchid != mchid {
		slog.Info("因商户号与预期不符，忽略微信支付通知", "notify_mchid", mchid, "config_mchid", service.mchid)
		return
	}
	if service.handler != nil {
		handler = service.handler
		return
	}
	service.handler, err = notify.NewRSANotifyHandler(cfg.MchV3Secret, verifiers.NewSHA256WithRSAVerifier(downloader.MgrInstance().GetCertificateVisitor(mchid)))
	if err != nil {
		return
	}
	handler = service.handler
	return
}
